import type {
  FormItemConfig,
  FormItemConfigList,
  ExtractFormStringifyFromObject,
} from "./types";
import _cloneDeep from "lodash/cloneDeep";

/** 检测是否忽略 */
const checkIsIgnore = (config: { ignore?: boolean; key: string }): boolean => {
  const { ignore, key } = config;
  return ignore || (key.startsWith("__") && key.toUpperCase() === key);
};

const isFn = (init: FormItemConfig["init"]): init is () => any => {
  return typeof init === "function";
};

/**
 * 生成表单数据
 */
export const generateFormData = <
  PO extends Record<string, any>,
  SO extends Record<string, any>,
>(
  list: FormItemConfigList<PO, SO>,
) => {
  return list.reduce<PO>(
    (acc, cur) => {
      if (checkIsIgnore(cur)) return acc;

      if (typeof cur.init === "object") {
        console.error(
          `表单项${cur.label}的初始值不能为对象 请设置为返回值的形式`,
        );
      }
      acc[cur.key as keyof PO] = isFn(cur.init)
        ? (cur.init() as any)
        : cur.init;
      return acc;
    },
    {} as unknown as PO,
  );
};

/**
 * 解析表单数据
 */
export const parseFormData = <
  PO extends Record<string, any>,
  SO extends Record<string, any>,
>(
  data: ExtractFormStringifyFromObject<PO, SO>,
  list: FormItemConfigList<PO, SO>,
) => {
  type PK = Extract<keyof PO, string>;

  const originData = _cloneDeep(data);
  return list.reduce<PO>(
    (acc, cur) => {
      if (checkIsIgnore(cur)) return acc;

      if (cur.parse) {
        const res = cur.parse(
          data[cur.key as unknown as keyof typeof data] as unknown as undefined,
          acc,
          originData,
        );
        if (res !== undefined) {
          acc[cur.key as PK] = res as Exclude<any, undefined>;
        }
      } else {
        acc[cur.key as PK] = (data as PO)[cur.key];
      }
      return acc;
    },
    {} as unknown as PO,
  );
};

/**
 * 序列化表单数据
 */
export const stringifyFormData = <
  PO extends Record<string, any>,
  SO extends Record<string, any>,
>(
  data: PO,
  list: FormItemConfigList<PO, SO>,
) => {
  type SR = ExtractFormStringifyFromObject<PO, SO>;
  type SRK = Extract<keyof SR, string>;

  const originData = _cloneDeep(data);
  return list.reduce<SR>(
    (acc, cur) => {
      if (checkIsIgnore(cur)) return acc;

      if (cur.stringify) {
        const res = cur.stringify(
          data[cur.key],
          acc as unknown as Partial<SR>,
          originData,
        );
        if (res !== undefined) {
          acc[cur.key as unknown as SRK] = res as Exclude<any, undefined>;
        }
      } else {
        acc[cur.key as unknown as SRK] = data[cur.key as any];
      }
      return acc;
    },
    {} as unknown as SR,
  );
};

/**
 * 获取v-model语法糖配置
 */
export const getVModelSugar = <
  PO extends Record<string, any>,
  SO extends Record<string, any>,
  PK extends Extract<keyof PO, string>,
  MK extends string,
>({
  modelValueKey = "modelValue" as MK,
  config,
  data,
  updateData = (val) => {
    data[config.key] = val;
  },
}: {
  modelValueKey?: MK;
  config: FormItemConfig<PO, SO>;
  data: PO;
  updateData?: (val: PO[PK]) => void;
}) => {
  return {
    [modelValueKey]: data[config.key],
    [`onUpdate:${modelValueKey}`]: (val: PO[PK]) => {
      updateData(val);
    },
  } as unknown as {
    [P in MK]: PO[PK];
  } & {
    [E in string as `onUpdate:${MK}`]: (val: PO[PK]) => void;
  };
};

/** 获取placeholder */
export const getPlaceholder = <
  PO extends Record<string, any>,
  SO extends Record<string, any>,
>(
  config: FormItemConfig<PO, SO>,
): {
  placeholder?: string;
} => {
  if (config.extra?.isInput) {
    return {
      placeholder: `请输入${config.label}`,
    };
  } else if (config.extra?.isSelect) {
    return {
      placeholder: `请选择${config.label}`,
    };
  } else {
    return {};
  }
};

/** 获取回车提交 */
export const getEnterSubmit = <
  PO extends Record<string, any>,
  SO extends Record<string, any>,
>(
  config: FormItemConfig<PO, SO>,
  handler: () => void,
) => {
  const { extra } = config;
  if (extra?.enterSubmit) {
    return {
      onKeyup: (e: KeyboardEvent) => {
        if (e.key === "Enter") {
          handler();
          (e.target as HTMLInputElement)?.blur?.();
        }
      },
    };
  }
};

/** 获取失去焦点提交 */
export const getBlurSubmit = <
  PO extends Record<string, any>,
  SO extends Record<string, any>,
>(
  config: FormItemConfig<PO, SO>,
  handler: () => void,
) => {
  const { extra } = config;
  if (extra?.isInput && (extra?.blurSubmit ?? true)) {
    return {
      onBlur: handler,
    };
  }
};

/** 获取变化提交 */
export const getChangeSubmit = <
  PO extends Record<string, any>,
  SO extends Record<string, any>,
>(
  config: FormItemConfig<PO, SO>,
  handler: () => void,
) => {
  const { extra } = config;
  if (extra?.isSelect && (extra?.changeSubmit ?? true)) {
    return {
      onChange: handler,
    };
  }
};
/** form item 更改loading状态 */
export const FORM_ITEM_CHANGE_LOADING = Symbol("FORM_ITEM_CHANGE_LOADING");
